package com.dayatang.exam.domain;

import java.text.NumberFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.hibernate.annotations.CacheConcurrencyStrategy;

import com.dayatang.domain.AbstractEntity;

/**
 * 试卷类�?每次考试将为每位考生生成�?��独一无二的试�?
 * 
 * @author yang
 * 
 */
@Entity
@Table(name = "EXAM_PAPERS")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class ExamPaper extends AbstractEntity {

	private static final long serialVersionUID = -8608009658834740423L;

	/**
	 * �?��考试
	 */
	@ManyToOne
	@JoinColumn(name = "EXAM_ID", nullable = false)
	private Exam exam;

	/**
	 * 试题相关信息
	 */
	@ManyToMany
	@JoinTable(name = "EXAM_QUESTIONS", 
			joinColumns = { @JoinColumn(name = "EXAM_PAPER_ID") }, 
			inverseJoinColumns = { @JoinColumn(name = "QUESTION_ID") })
	private Set<Question> questions = new HashSet<Question>();

	public ExamPaper() {
	}

	public Exam getExam() {
		return exam;
	}

	public void setExam(Exam exam) {
		this.exam = exam;
	}

	public Set<Question> getQuestions() {
		return questions;
	}

	public void addQuestion(Question question) {
		questions.add(question);
	}

	public void addQuestions(Collection<Question> questionsToBeAdded) {
		questions.addAll(questionsToBeAdded);
	}

	public static ExamPaper create(Exam exam) {
		ExamPaper result = new ExamPaper();
		result.setExam(exam);
		for (ExamQuestionInfo questionInfo : exam.getQuestionInfos()) {
			result.addQuestions(questionInfo.generateQuestions());
		}
		result.save();
		return result;
	}
	
	
	/**
	 * 获取题库中指定类型的全部试题
	 * 
	 * @param questionClass
	 *            试题的子类型
	 * @return
	 */
	public <T extends Question> List<T> listQuestions(Class<T> QuestionClass) {
		return questionRepository.listQuestions(this, QuestionClass);

	}

	/**
	 * 获取单�?题的集合
	 * 
	 * @return
	 */
	public List<SingleChoiceQuestion> getSingleChoiceQuestions() {
		return listQuestions(SingleChoiceQuestion.class);
	}

	/**
	 * 获取多�?题的集合
	 * 
	 * @return
	 */
	public List<MultiChoiceQuestion> getMultiChoiceQuestions() {
		return listQuestions(MultiChoiceQuestion.class);
	}

	/**
	 * 获得判断题的集合
	 * 
	 * @return
	 */
	public List<JudgementQuestion> getJudgementQuestions() {
		return listQuestions(JudgementQuestion.class);
	}

	/**
	 * 获得填空题的集合
	 * 
	 * @return
	 */
	public List<FillBlankQuestion> getFillBlankQuestions() {
		return listQuestions(FillBlankQuestion.class);
	}

	/**
	 * 获得问答题的集合
	 * 
	 * @return
	 */
	public List<QuizQuestion> getQuizQuestions() {
		return listQuestions(QuizQuestion.class);
	}

	/**
	 * 获得单�?题的数量
	 * 
	 * @return
	 */
	public int getSingleChoiceCount() {
		return getSingleChoiceQuestions().size();
	}

	/**
	 * 获得多�?题的数量
	 * 
	 * @return
	 */
	public int getMultiChoiceCount() {
		return getMultiChoiceQuestions().size();
	}

	/**
	 * 获得判断题的数量
	 * 
	 * @return
	 */
	public int getJudgementCount() {
		return getJudgementQuestions().size();
	}

	/**
	 * 获得填空题的数量
	 * 
	 * @return
	 */
	public int getFillBlankCount() {
		return getFillBlankQuestions().size();
	}

	/**
	 * 获得问答题的数量
	 * 
	 * @return
	 */
	public int getQuizCount() {
		return getQuizQuestions().size();
	}

	/**
	 * 获得未提交的答题的数�?
	 * 
	 * @param QuestionType
	 * @return
	 */
	public int getUnSubmitedQuestionCount(Class<? extends Question> QuestionClass) {
		return questionRepository.getUnSubmitedQuestionCount(this, QuestionClass);
	}

	/**
	 * 获得试卷总分
	 * 
	 * @return
	 */
	public int getPoint() {
		return exam.getPoint();
	}

	public boolean isPassed() {
		return getScore() > exam.getPassPoint();
	}

	public boolean isScored() {
		return status == STATUS_SCORED;
	}

	public boolean isSubmitted() {
		return status == STATUS_SUBMITTED;
	}

	@Override
	public boolean equals(final Object other) {
		if (!(other instanceof ExamPaper))
			return false;
		ExamPaper castOther = (ExamPaper) other;
		return new EqualsBuilder().append(getId(), castOther.getId()).append(user, castOther.user).isEquals();
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder().append(getId()).append(user).toHashCode();
	}

	@Override
	public String toString() {
		return new ToStringBuilder(this).append("id", getId()).append("user", user).append("exam", exam).toString();
	}

	public int compareTo(ExamPaper other) {
		if (other == null) {
			return 1;
		}
		return score > other.getScore() ? -1 : 1;
	}

	private static ExamPaperRepository examPaperRepository;

	private static QuestionRepository questionRepository;

	public void setExamPaperRepository(ExamPaperRepository examPaperRepository) {
		ExamPaper.examPaperRepository = examPaperRepository;
	}

	public void setQuestionRepository(QuestionRepository questionRepository) {
		ExamPaper.questionRepository = questionRepository;
	}

	public static ExamPaper get(Long id) {
		return getRepository(ExamPaper.class, id);
	}

	public static ExamPaper get(Exam exam, User user) {
		return examPaperRepository.get(exam, user);
	}

	/**
	 * 按�?试和用户的范例查找试�?
	 * 
	 * @param exam
	 * @param user
	 * @return
	 */
	public static Collection<ExamPaper> findByExample(Exam exam, User user) {
		return examPaperRepository.findByExample(exam, user);
	}

	/**
	 * 按�?试和用户查找未批阅的试卷
	 * 
	 * @param exam
	 * @param user
	 * @param organization
	 * @return
	 */
	public static Collection<ExamPaper> findUnScored(Exam exam, User user, Organization organization) {
		return examPaperRepository.listUnScored(exam, user, organization);
	}

	/**
	 * 列出指定阅卷人能够阅卷的�?��试卷
	 * 
	 * @param currentUser
	 * @return
	 */
	public static Collection<ExamPaper> findByValuator(User user) {
		return examPaperRepository.findByValuator(user);
	}

	/**
	 * 查找试卷
	 * 
	 * @param exam
	 *            �?��的�?�?
	 * @param student
	 *            考生
	 * @param organization
	 *            考生单位
	 * @param position
	 *            考生岗位
	 * @return
	 */
	public static Collection<ExamPaper> find(Exam exam, User student, Organization organization, int position) {
		return examPaperRepository.find(exam, student, organization, position);
	}

	/**
	 * 列出指定用户以往的�?试情�?
	 * 
	 * @param user
	 * @return
	 */
	public static Collection<ExamPaper> listFinished(User user) {
		return examPaperRepository.listFinished(user);
	}

	/**
	 * 获取已经阅卷的试�?
	 * 
	 * @return
	 */
	public static Collection<ExamPaper> listScored(Exam exam) {
		return examPaperRepository.listScored(exam);
	}

	/**
	 * 获取已提交的试卷
	 * 
	 * @param exam
	 * @return
	 */
	public static Collection<ExamPaper> listSubmitted(Exam exam) {
		return examPaperRepository.listSubmitted(exam);
	}

	/**
	 * 考生交卷
	 */
	public void submit() {
		submitTime = Calendar.getInstance().getTime();
		calculateObjectiveScore();
		status = STATUS_SUBMITTED;
		save();
	}

	/**
	 * 计算客观题得�?
	 */
	public void calculateObjectiveScore() {
		singleChoiceScore = 0;
		multiChoiceScore = 0;
		judgementScore = 0;
		for (SingleChoiceQuestion Question : getSingleChoiceQuestions()) {
			Question.calculateScore();
			Question.save();
			singleChoiceScore += Question.getScore();
		}
		for (MultiChoiceQuestion Question : getMultiChoiceQuestions()) {
			Question.calculateScore();
			Question.save();
			multiChoiceScore += Question.getScore();
		}
		for (JudgementQuestion Question : getJudgementQuestions()) {
			Question.calculateScore();
			Question.save();
			judgementScore += Question.getScore();
		}
		objectiveScore = singleChoiceScore + multiChoiceScore + judgementScore;
		score = objectiveScore;
	}

	/**
	 * 阅卷评分
	 */
	public void score() {
		scoreTime = Calendar.getInstance().getTime();
		calculateSubjectiveScore();
		status = STATUS_SCORED;
		save();
	}

	/**
	 * 计算主观题得分和总分
	 */
	public void calculateSubjectiveScore() {
		fillBlankScore = 0;
		quizScore = 0;
		for (FillBlankQuestion Question : getFillBlankQuestions()) {
			fillBlankScore += Question.getScore();
		}
		for (QuizQuestion Question : getQuizQuestions()) {
			multiChoiceScore += Question.getScore();
		}
		score = objectiveScore + fillBlankScore + quizScore;
	}

	public int getExamPaperCountByExam(Exam exam) {
		return examPaperRepository.getPaperCountOf(exam);
	}

	/**
	 * 获得剩余时间
	 * 
	 * @return
	 */
	public long getRemainSeconds() {
		long result = (toTime.getTime() - System.currentTimeMillis()) / 1000;
		return result > 0 ? result : 0;
	}

	/**
	 * 获得试卷剩余时间(考试监控)
	 * 
	 * @return
	 */
	public long getRemainMinutes() {
		long result = (toTime.getTime() - System.currentTimeMillis()) / 1000 / 60;
		return result > 0 ? result : 0;
	}

	/**
	 * 获得完成�?
	 * 
	 * @return
	 */
	public double getCompletionRate() {
		if (questions.isEmpty()) {
			return 0;
		}
		return (double) getCompletedQuestionCount() / questions.size();
	}

	private int getCompletedQuestionCount() {
		return examPaperRepository.getCompletedQuestionCountOf(this);
	}

	public String getCompletionRatePercent() {
		if (getCompletionRate() >= 1) {
			return 1 * 100 + "%";
		} else {
			return NumberFormat.getPercentInstance().format(getCompletionRate());
		}
	}
}
